/**
* Copyright (c) By zengqh.
*
* This program is just for fun or demo, in the hope that it  
* will be useful, you can redistribute it and/or modify freely.
*
* Time: 2013/02/18
* File: ray.h
**/

#pragma once

#include "vector3.h"

namespace HY
{
class BoundingBox;
class Frustum;
class Plane;
class Sphere;

/// Infinite straight line in three-dimensional space.
class Ray
{
public:
	/// Construct undefined.
	Ray()
	{
	}

	/// Construct from origin and direction. The direction must be normalized.
	Ray(const Vector3& origin, const Vector3& direction) :
	origin_(origin),
		direction_(direction)
	{
	}

	/// Copy-construct from another ray.
	Ray(const Ray& ray) :
	origin_(ray.origin_),
		direction_(ray.direction_)
	{
	}

	/// Assign from another ray.
	Ray& operator = (const Ray& rhs)
	{
		origin_ = rhs.origin_;
		direction_ = rhs.direction_;
		return *this;
	}

	/// Check for equality with another ray.
	bool operator == (const Ray& rhs) const { return origin_ == rhs.origin_ && direction_ == rhs.direction_; }
	/// Check for inequality with another ray.
	bool operator != (const Ray& rhs) const { return origin_ != rhs.origin_ || direction_ != rhs.direction_; }

	/// Define from origin and direction. The direction will be normalized.
	void Define(const Vector3& origin, const Vector3& direction)
	{
		origin_ = origin;
		direction_ = direction.Normalized();
	}

	/// Project a point on the ray.
	Vector3 Project(const Vector3& point) const;
	/// Return distance of a point from the ray
	float Distance(const Vector3& point) const;
	/// Return closest point to another ray.
	Vector3 ClosestPoint(const Ray& ray) const;
	/// Return hit distance to a plane, or infinity if no hit.
	float HitDistance(const Plane& plane) const;
	/// Return hit distance to a bounding box, or infinity if no hit.
	float HitDistance(const BoundingBox& box) const;
	/// Return hit distance to a frustum, or infinity if no hit.
	float HitDistance(const Frustum& frustum) const;
	/// Return hit distance to a sphere, or infinity if no hit.
	float HitDistance(const Sphere& sphere) const;
	/// Return hit distance to a triangle, or infinity if no hit.
	float HitDistance(const Vector3& v0, const Vector3& v1, const Vector3& v2) const;
	/// Return hit distance to a triangle mesh defined by vertex and index data, or infinity if no hit.
	float HitDistance(const void* vertexData, unsigned vertexSize, const void* indexData, unsigned indexSize, unsigned indexStart, unsigned indexCount) const;

	/// Ray origin.
	Vector3 origin_;
	/// Ray direction.
	Vector3 direction_;
};
}